/*
 * LogFile.cpp
 */

#include "LogFile.h"
#include <stdio.h>
#define ACCESS_LOG_FILENAME "access.log"
#define ERROR_LOG_FILENAME "error.log"
#define INI_DATE "["
#define END_DATE "]"
#define SEPARATOR " "
#define RESOURCE_SEPARATOR "\""
#define INFO "INFO"
#define ERROR "ERROR"

LogFileException::LogFileException(const std::string& msg) throw() {
	this->msg = msg;
}

const char* LogFileException::what() const throw() {
	return msg.c_str();
}

LogFile::LogFile(const std::string& logDir, bool writeMode) {
	outMode = writeMode;
	accessFileName.assign(logDir + ACCESS_LOG_FILENAME);
	errorFileName.assign(logDir + ERROR_LOG_FILENAME);
	if (outMode) {
		accessFile.open(accessFileName.c_str(), std::fstream::out | std::fstream::app);
		if (!accessFile.is_open())
			throw LogFileException("No se pudo abrir el archivo de log de "
					"acceso para escritura");
		errorFile.open(errorFileName.c_str(), std::fstream::out | std::fstream::app);
		if (!errorFile.is_open())
			throw LogFileException("No se pudo abrir el archivo de log de "
					"errores para escritura");
	}
	else {
		accessFile.open(accessFileName.c_str(), std::fstream::in);
		errorFile.open(errorFileName.c_str(), std::fstream::in);
	}
}

LogFile::~LogFile() {
	removeIfEmptyFile(accessFile, accessFileName);
	removeIfEmptyFile(errorFile, errorFileName);
}

void LogFile::removeIfEmptyFile(std::fstream& file, const std::string& fileName) {
	if (file.is_open()) {
		file.seekg(0, std::fstream::end);
		std::ios::pos_type tam = file.tellg();
		file.close();
		// Si el archivo esta vacio, lo borro
		if (tam == 0)
			remove( fileName.c_str() );
	}
}

void LogFile::addAccessInfo(const std::string& requestLine, int statusCode) {
	if (outMode) {
		Lock lock(accessFile_Mutex);
		accessFile << INI_DATE << TimeUtils::rfc1123TimeStamp() << END_DATE;
		accessFile << SEPARATOR << RESOURCE_SEPARATOR;
		accessFile << requestLine.substr(0, requestLine.find_first_of("\r\n"));
		accessFile << RESOURCE_SEPARATOR << SEPARATOR << statusCode << "\n";
		accessFile.flush();
	}
}

void LogFile::addAccessError(const std::string& requestLine, int statusCode) {
	if (outMode) {
		Lock lock(errorFile_Mutex);
		errorFile << INI_DATE << TimeUtils::rfc1123TimeStamp() << END_DATE;
		errorFile << SEPARATOR << RESOURCE_SEPARATOR;
		errorFile << requestLine.substr(0, requestLine.find_first_of("\r\n"));
		errorFile << RESOURCE_SEPARATOR << SEPARATOR << statusCode << "\n";
		errorFile.flush();
	}
}

void LogFile::addInfo(const std::string& info) {
	if (outMode) {
		Lock lock(accessFile_Mutex);
		accessFile << INI_DATE << TimeUtils::rfc1123TimeStamp() << END_DATE;
		accessFile << SEPARATOR << INFO << SEPARATOR << info << "\n";
		accessFile.flush();
	}
}

void LogFile::addError(const std::string& error) {
	if (outMode) {
		Lock lock(errorFile_Mutex);
		errorFile << INI_DATE << TimeUtils::rfc1123TimeStamp() << END_DATE;
		errorFile << SEPARATOR << ERROR << SEPARATOR << error << "\n";
		errorFile.flush();
	}
}

void LogFile::rewind(std::fstream& archivo) {
	if (!outMode) {
		archivo.seekg(0, std::fstream::beg);
		archivo.clear();
	}
}

bool LogFile::getLine(std::string& line, std::fstream& archivo) {
	if (!outMode) {
		std::getline(archivo, line);
		return (!archivo.eof() && !archivo.fail());
	}
	return false;
}

void LogFile::rewindAccessFile() {
	rewind(accessFile);
}

bool LogFile::getLineAccessFile(std::string& line) {
	return getLine(line, accessFile);

}

void LogFile::rewindErrorFile() {
	rewind(errorFile);
}

bool LogFile::getLineErrorFile(std::string& line) {
	return getLine(line, errorFile);
}
